package com.twt.config.mybatis.surppot;

import com.twt.config.mybatis.MybatisDataSourceProperty;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import java.util.*;

/**
 * @author: tangwt
 * @date: 2022/5/19 21:54
 * @version:1.0
 **/
@Slf4j
public abstract class AbstractDataSourceBuilder implements DataSourceBuilder {
    protected BeanDefinitionRegistry registry;
    protected MybatisDataSourceProperty dataSourceProperty;
    protected String beanName;

    public void setBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        this.registry = registry;
    }

    public void setMybatisDataSourceProperty(MybatisDataSourceProperty dataSourceProperty) {
        this.dataSourceProperty = dataSourceProperty;
    }

    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }

    @Override
    public void registry() {
        if (log.isDebugEnabled()){
            log.info("数据源【{}】开始注册",beanName);
        }
        this.registryDataSource();
        this.registryTransactionManger();
        this.registrySqlSessionFactory();
        this.registryMapperScanner();
        this.registrySqlSessionTemplate();
        if (log.isDebugEnabled()){
            log.info("数据源【{}】注册完成",beanName);
        }

    }

    /**
     * @Description: 注册数据源
     * @Author: TWT
     * @Date: 11:50 2022/6/3
     * @param:[]
     * @return:void
     **/
    protected abstract void registryDataSource();

    /**
     * @Description: 注册事务
     * @Author: TWT
     * @Date: 11:48 2022/6/3
     * @param:[]
     * @return:void
     **/
    protected void registryTransactionManger() {

        Map<String, Object> dstmMap = new HashMap<>(16);
        dstmMap.put("dataSource", new RuntimeBeanReference(beanName));
        this.registerBean(beanName + "TransactionManager", dstmMap, this.getTransactionManagerClass());
        if (log.isDebugEnabled()){
            log.info("事务【{}】",beanName + "TransactionManager");
        }
    }

    /** 注册 sqlSessionFactory
     * @Description:
     * @Author: TWT
     * @Date: 11:49 2022/6/3
     * @param:[]
     * @return:void
     **/
    protected void registrySqlSessionFactory() {

        Map<String, Object> sqlMap = new HashMap(8);
        sqlMap.put("dataSource", new RuntimeBeanReference(beanName));
        List<String> typeAliasesPackageList = this.dataSourceProperty.getTypeAliasesPackage();
        List<String> mapperLocationsList = this.dataSourceProperty.getMapperLocations();
        sqlMap.put("typeAliasesPackage", typeAliasesPackageList);
        sqlMap.put("mapperLocations", mapperLocationsList);
//        sqlMap.put("databaseIdProvider", this.buildDatabaseIdProvider());
//        sqlMap.put("typeHandlers", this.buildTypeHandle());
        sqlMap.putAll(Optional.ofNullable(this.dataSourceProperty.getSqlSessionExtendMap()).orElse(new HashMap<>(16)));
        this.registerBean(beanName + "SqlSessionFactory", sqlMap, this.getSqlSessionFactoryBean());
        if (log.isDebugEnabled()){
            log.info("sqlSessionFactory【{}】",beanName + "SqlSessionFactory");
        }
    }
    /**
     * @Description: 注册mapperScanner
     * @Author: TWT
     * @Date: 13:44 2022/6/3
     * @param:[]
     * @return:void
     **/
    protected void registryMapperScanner(){
        Map<String,Object> mapperMap = new HashMap<>(16);
        mapperMap.put("basePackage", dataSourceProperty.getMappers());
        mapperMap.put("sqlSessionFactoryBeanName", beanName + "SqlSessionFactory");
        this.registerBean(beanName + "MapperScanner", mapperMap, this.getMapperScannerClass());
    }
    /**
     * @Description: 注册SqlSessionTemplate
     * @Author: TWT
     * @Date: 13:45 2022/6/3
     * @param:[]
     * @return:void
     **/
    protected void registrySqlSessionTemplate(){
        BeanDefinitionBuilder dbBuilder = BeanDefinitionBuilder.rootBeanDefinition(SqlSessionTemplate.class);
        RootBeanDefinition dbBeanDefinition = (RootBeanDefinition)dbBuilder.getBeanDefinition();
        dbBeanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, new RuntimeBeanReference(beanName + "SqlSessionFactory"));
        registry.registerBeanDefinition(beanName + "SqlSessionTemplate", dbBeanDefinition);
    }


    protected void registerBean(String beanName, Map<String, Object> attributeMap, Class clazz) {
        BeanDefinitionBuilder dbBuilder = BeanDefinitionBuilder.rootBeanDefinition(clazz);
        RootBeanDefinition dbBeanDefinition = (RootBeanDefinition) dbBuilder.getBeanDefinition();
        dbBeanDefinition.getPropertyValues().addPropertyValues(attributeMap);
        this.registry.registerBeanDefinition(beanName, dbBeanDefinition);
    }

    protected abstract Class getDataSourceClass();

    protected Class getSqlSessionFactoryBean() {
        return SqlSessionFactoryBean.class;
    }
    protected Class getMapperScannerClass() {
        return MapperScannerConfigurer.class;
    }

    protected Class getTransactionManagerClass() {
        return DataSourceTransactionManager.class;
    }
}
